From 5738920196ebb7962d7cfc8c2982b8540ab0703c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 8 Jul 2017 19:45:07 +0300 Subject: [PATCH] Restructure code --- src/cargo/util/toml/mod.rs | 94 +--------- src/cargo/util/toml/targets.rs | 311 +++++++++++++++++++++------------ 2 files changed, 211 insertions(+), 194 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index e2c7d08f9..15fa98bbe 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -42,7 +42,8 @@ fn do_read_manifest(contents: &str, let project_root = manifest_file.parent().unwrap(); let toml = { - let pretty_filename = util::without_prefix(manifest_file, config.cwd()).unwrap_or(manifest_file); + let pretty_filename = + util::without_prefix(manifest_file, config.cwd()).unwrap_or(manifest_file); parse(contents, pretty_filename, config)? }; @@ -516,7 +517,7 @@ impl TomlManifest { // If we have no lib at all, use the inferred lib if available // If we have a lib with a path, we're done // If we have a lib with no path, use the inferred lib or_else package name - let targets = targets(me, project_root, project_name, &project.build)?; + let targets = targets(me, project_name, project_root, &project.build)?; if targets.is_empty() { debug!("manifest has no build targets"); @@ -964,94 +965,13 @@ impl TomlTarget { } } - fn validate_library_name(&self) -> CargoResult<()> { - match self.name { - Some(ref name) => { - if name.trim().is_empty() { - Err("library target names cannot be empty.".into()) - } else if name.contains('-') { - Err(format!("library target names cannot contain hyphens: {}", - name).into()) - } else { - Ok(()) - } - }, - None => Ok(()) - } - } - - fn validate_binary_name(&self) -> CargoResult<()> { - match self.name { - Some(ref name) => { - if name.trim().is_empty() { - Err("binary target names cannot be empty.".into()) - } else { - Ok(()) - } - }, - None => Err("binary target bin.name is required".into()) - } - } - - fn validate_example_name(&self) -> CargoResult<()> { - match self.name { - Some(ref name) => { - if name.trim().is_empty() { - Err("example target names cannot be empty".into()) - } else { - Ok(()) - } - }, - None => Err("example target example.name is required".into()) - } - } - - fn validate_test_name(&self) -> CargoResult<()> { - match self.name { - Some(ref name) => { - if name.trim().is_empty() { - Err("test target names cannot be empty".into()) - } else { - Ok(()) - } - }, - None => Err("test target test.name is required".into()) - } - } - - fn validate_bench_name(&self) -> CargoResult<()> { - match self.name { - Some(ref name) => { - if name.trim().is_empty() { - Err("bench target names cannot be empty".into()) - } else { - Ok(()) - } - }, - None => Err("bench target bench.name is required".into()) - } - } - - fn validate_crate_type(&self) -> CargoResult<()> { - // Per the Macros 1.1 RFC: - // - // > Initially if a crate is compiled with the proc-macro crate type - // > (and possibly others) it will forbid exporting any items in the - // > crate other than those functions tagged #[proc_macro_derive] and - // > those functions must also be placed at the crate root. - // - // A plugin requires exporting plugin_registrar so a crate cannot be - // both at once. - if self.plugin == Some(true) && self.proc_macro() == Some(true) { - Err("lib.plugin and lib.proc-macro cannot both be true".into()) - } else { - Ok(()) - } - } - fn proc_macro(&self) -> Option { self.proc_macro.or(self.proc_macro2) } + + fn crate_types(&self) -> Option<&Vec> { + self.crate_type.as_ref().or(self.crate_type2.as_ref()) + } } impl fmt::Debug for PathValue { diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index 588b2d676..d5ec3a96d 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -20,98 +20,14 @@ use super::{TomlTarget, LibKind, PathValue, TomlManifest, StringOrBool, TomlLibTarget, TomlBinTarget, TomlBenchTarget, TomlExampleTarget, TomlTestTarget}; -/// Implicit Cargo targets, defined by conventions. -struct Layout { - root: PathBuf, - lib: Option, - bins: Vec, - examples: Vec, - tests: Vec, - benches: Vec, -} - -impl Layout { - /// Returns a new `Layout` for a given root path. - /// The `root_path` represents the directory that contains the `Cargo.toml` file. - pub fn from_project_path(root_path: &Path) -> Layout { - let mut lib = None; - let mut bins = vec![]; - let mut examples = vec![]; - let mut tests = vec![]; - let mut benches = vec![]; - - let lib_candidate = root_path.join("src").join("lib.rs"); - if fs::metadata(&lib_candidate).is_ok() { - lib = Some(lib_candidate); - } - - try_add_file(&mut bins, root_path.join("src").join("main.rs")); - try_add_files(&mut bins, root_path.join("src").join("bin")); - try_add_mains_from_dirs(&mut bins, root_path.join("src").join("bin")); - - try_add_files(&mut examples, root_path.join("examples")); - - try_add_files(&mut tests, root_path.join("tests")); - try_add_files(&mut benches, root_path.join("benches")); - - Layout { - root: root_path.to_path_buf(), - lib: lib, - bins: bins, - examples: examples, - tests: tests, - benches: benches, - } - } -} - -fn try_add_file(files: &mut Vec, file: PathBuf) { - if fs::metadata(&file).is_ok() { - files.push(file); - } -} - -// Add directories form src/bin which contain main.rs file -fn try_add_mains_from_dirs(files: &mut Vec, root: PathBuf) { - if let Ok(new) = fs::read_dir(&root) { - let new: Vec = new.filter_map(|i| i.ok()) - // Filter only directories - .filter(|i| { - i.file_type().map(|f| f.is_dir()).unwrap_or(false) - // Convert DirEntry into PathBuf and append "main.rs" - }).map(|i| { - i.path().join("main.rs") - // Filter only directories where main.rs is present - }).filter(|f| { - f.as_path().exists() - }).collect(); - files.extend(new); - } -} - -fn try_add_files(files: &mut Vec, root: PathBuf) { - if let Ok(new) = fs::read_dir(&root) { - files.extend(new.filter_map(|dir| { - dir.map(|d| d.path()).ok() - }).filter(|f| { - f.extension().and_then(|s| s.to_str()) == Some("rs") - }).filter(|f| { - // Some unix editors may create "dotfiles" next to original - // source files while they're being edited, but these files are - // rarely actually valid Rust source files and sometimes aren't - // even valid UTF-8. Here we just ignore all of them and require - // that they are explicitly specified in Cargo.toml if desired. - f.file_name().and_then(|s| s.to_str()).map(|s| { - !s.starts_with('.') - }).unwrap_or(true) - })) - } - /* else just don't add anything if the directory doesn't exist, etc. */ -} - -pub fn targets(me: &TomlManifest, project_root: &Path, project_name: &str, custom_build: &Option) -> CargoResult> { +pub fn targets(manifest: &TomlManifest, + project_name: &str, + project_root: &Path, + custom_build: &Option) + -> CargoResult> { let layout = Layout::from_project_path(project_root); - let lib = match me.lib { + + let lib = match manifest.lib { Some(ref lib) => { lib.validate_library_name()?; lib.validate_crate_type()?; @@ -128,7 +44,7 @@ pub fn targets(me: &TomlManifest, project_root: &Path, project_name: &str, custo None => inferred_lib_target(project_name, &layout), }; - let bins = match me.bin { + let bins = match manifest.bin { Some(ref bins) => { for target in bins { target.validate_binary_name()?; @@ -145,7 +61,7 @@ pub fn targets(me: &TomlManifest, project_root: &Path, project_name: &str, custo } } - let examples = match me.example { + let examples = match manifest.example { Some(ref examples) => { for target in examples { target.validate_example_name()?; @@ -155,7 +71,7 @@ pub fn targets(me: &TomlManifest, project_root: &Path, project_name: &str, custo None => inferred_example_targets(&layout) }; - let tests = match me.test { + let tests = match manifest.test { Some(ref tests) => { for target in tests { target.validate_test_name()?; @@ -165,7 +81,7 @@ pub fn targets(me: &TomlManifest, project_root: &Path, project_name: &str, custo None => inferred_test_targets(&layout) }; - let benches = match me.bench { + let benches = match manifest.bench { Some(ref benches) => { for target in benches { target.validate_bench_name()?; @@ -177,26 +93,26 @@ pub fn targets(me: &TomlManifest, project_root: &Path, project_name: &str, custo if let Err(e) = unique_names_in_targets(&bins) { bail!("found duplicate binary name {}, but all binary targets \ - must have a unique name", e); + must have a unique name", e); } if let Err(e) = unique_names_in_targets(&examples) { bail!("found duplicate example name {}, but all binary targets \ - must have a unique name", e); + must have a unique name", e); } if let Err(e) = unique_names_in_targets(&benches) { - bail!("found duplicate bench name {}, but all binary targets must \ - have a unique name", e); + bail!("found duplicate bench name {}, but all binary targets \ + must have a unique name", e); } if let Err(e) = unique_names_in_targets(&tests) { - bail!("found duplicate test name {}, but all binary targets must \ - have a unique name", e) + bail!("found duplicate test name {}, but all binary targets \ + must have a unique name", e) } // processing the custom build script - let new_build = me.maybe_custom_build(custom_build, &layout.root); + let new_build = manifest.maybe_custom_build(custom_build, &layout.root); // Get targets let targets = normalize(&layout.root, @@ -209,6 +125,184 @@ pub fn targets(me: &TomlManifest, project_root: &Path, project_name: &str, custo Ok(targets) } + +/// Implicit Cargo targets, defined by conventions. +struct Layout { + root: PathBuf, + lib: Option, + bins: Vec, + examples: Vec, + tests: Vec, + benches: Vec, +} + +impl Layout { + /// Returns a new `Layout` for a given root path. + /// The `root_path` represents the directory that contains the `Cargo.toml` file. + fn from_project_path(root_path: &Path) -> Layout { + let mut lib = None; + let mut bins = vec![]; + let mut examples = vec![]; + let mut tests = vec![]; + let mut benches = vec![]; + + let lib_candidate = root_path.join("src").join("lib.rs"); + if fs::metadata(&lib_candidate).is_ok() { + lib = Some(lib_candidate); + } + + try_add_file(&mut bins, root_path.join("src").join("main.rs")); + try_add_files(&mut bins, root_path.join("src").join("bin")); + try_add_mains_from_dirs(&mut bins, root_path.join("src").join("bin")); + + try_add_files(&mut examples, root_path.join("examples")); + + try_add_files(&mut tests, root_path.join("tests")); + try_add_files(&mut benches, root_path.join("benches")); + + return Layout { + root: root_path.to_path_buf(), + lib: lib, + bins: bins, + examples: examples, + tests: tests, + benches: benches, + }; + + fn try_add_file(files: &mut Vec, file: PathBuf) { + if fs::metadata(&file).is_ok() { + files.push(file); + } + } + + // Add directories form src/bin which contain main.rs file + fn try_add_mains_from_dirs(files: &mut Vec, root: PathBuf) { + if let Ok(new) = fs::read_dir(&root) { + let new: Vec = new.filter_map(|i| i.ok()) + // Filter only directories + .filter(|i| { + i.file_type().map(|f| f.is_dir()).unwrap_or(false) + // Convert DirEntry into PathBuf and append "main.rs" + }).map(|i| { + i.path().join("main.rs") + // Filter only directories where main.rs is present + }).filter(|f| { + f.as_path().exists() + }).collect(); + files.extend(new); + } + } + + fn try_add_files(files: &mut Vec, root: PathBuf) { + if let Ok(new) = fs::read_dir(&root) { + files.extend(new.filter_map(|dir| { + dir.map(|d| d.path()).ok() + }).filter(|f| { + f.extension().and_then(|s| s.to_str()) == Some("rs") + }).filter(|f| { + // Some unix editors may create "dotfiles" next to original + // source files while they're being edited, but these files are + // rarely actually valid Rust source files and sometimes aren't + // even valid UTF-8. Here we just ignore all of them and require + // that they are explicitly specified in Cargo.toml if desired. + f.file_name().and_then(|s| s.to_str()).map(|s| { + !s.starts_with('.') + }).unwrap_or(true) + })) + } + /* else just don't add anything if the directory doesn't exist, etc. */ + } + } +} + +impl TomlTarget { + fn validate_library_name(&self) -> CargoResult<()> { + match self.name { + Some(ref name) => { + if name.trim().is_empty() { + Err("library target names cannot be empty.".into()) + } else if name.contains('-') { + Err(format!("library target names cannot contain hyphens: {}", + name).into()) + } else { + Ok(()) + } + }, + None => Ok(()) + } + } + + fn validate_binary_name(&self) -> CargoResult<()> { + match self.name { + Some(ref name) => { + if name.trim().is_empty() { + Err("binary target names cannot be empty.".into()) + } else { + Ok(()) + } + }, + None => Err("binary target bin.name is required".into()) + } + } + + fn validate_example_name(&self) -> CargoResult<()> { + match self.name { + Some(ref name) => { + if name.trim().is_empty() { + Err("example target names cannot be empty".into()) + } else { + Ok(()) + } + }, + None => Err("example target example.name is required".into()) + } + } + + fn validate_test_name(&self) -> CargoResult<()> { + match self.name { + Some(ref name) => { + if name.trim().is_empty() { + Err("test target names cannot be empty".into()) + } else { + Ok(()) + } + }, + None => Err("test target test.name is required".into()) + } + } + + fn validate_bench_name(&self) -> CargoResult<()> { + match self.name { + Some(ref name) => { + if name.trim().is_empty() { + Err("bench target names cannot be empty".into()) + } else { + Ok(()) + } + }, + None => Err("bench target bench.name is required".into()) + } + } + + fn validate_crate_type(&self) -> CargoResult<()> { + // Per the Macros 1.1 RFC: + // + // > Initially if a crate is compiled with the proc-macro crate type + // > (and possibly others) it will forbid exporting any items in the + // > crate other than those functions tagged #[proc_macro_derive] and + // > those functions must also be placed at the crate root. + // + // A plugin requires exporting plugin_registrar so a crate cannot be + // both at once. + if self.plugin == Some(true) && self.proc_macro() == Some(true) { + Err("lib.plugin and lib.proc-macro cannot both be true".into()) + } else { + Ok(()) + } + } +} + + fn normalize(package_root: &Path, lib: &Option, bins: &[TomlBinTarget], @@ -234,11 +328,15 @@ fn normalize(package_root: &Path, let path = l.path.clone().unwrap_or_else( || PathValue(Path::new("src").join(&format!("{}.rs", l.name()))) ); - let crate_types = l.crate_type.as_ref().or(l.crate_type2.as_ref()); - let crate_types = match crate_types { + let crate_types = match l.crate_types() { Some(kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(), None => { - vec![if l.plugin == Some(true) { LibKind::Dylib } else if l.proc_macro() == Some(true) { LibKind::ProcMacro } else { LibKind::Lib }] + let lib_kind = match (l.plugin, l.proc_macro()) { + (Some(true), _) => LibKind::Dylib, + (_, Some(true)) => LibKind::ProcMacro, + _ => LibKind::Lib + }; + vec![lib_kind] } }; @@ -276,8 +374,7 @@ fn normalize(package_root: &Path, PathValue(default(ex)) }); - let crate_types = ex.crate_type.as_ref().or(ex.crate_type2.as_ref()); - let crate_types = match crate_types { + let crate_types = match ex.crate_types() { Some(kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(), None => Vec::new() }; -- 2.30.2